using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Ltf.Remoting.RemoteEvents;
using Microsoft.TeamFoundation.VersionControl.Client;
using Ltf.Remoting.TeamFoundation;
using Ltf.Remoting.TFAccess;
using System.Collections;
using Ltf.MonitorLizard.Helpers;
using System.IO;

namespace Ltf.MonitorLizard.Forms
{

	[FormType(FormTypes.Labels)]

	public partial class Labels : Form
	{
		private Workspace workspace;
		private string path;
		private string serverPath;
		private VersionControlLabel currentLabel = null;
		private Queue<LabelUpdateOperation> pendingUpdates;

		private TFServerConnection connection;

		public Labels(string[] pathList, LizardEventArgs args)
			: this(pathList[0])
		{

		}

		public Labels(string path)
		{
			InitializeComponent();
			connection = ServerConnections.GetConnectionForPath(path);
			sortColumnIndex = new Dictionary<ListView, int>();
			sortColumnIndex.Add(lvwLabels, 0);
			sortColumnIndex.Add(lvwItems, 0);
			sortDesc = new Dictionary<ListView, bool>();
			sortDesc.Add(lvwLabels, false);
			sortDesc.Add(lvwItems, false);
			sortitems = new Dictionary<ListView, VirtualViewItem[]>();
			sortitems.Add(lvwLabels, VirtualViewItemsLabels);
			sortitems.Add(lvwItems, VirtualViewItemsLabelItems);

			this.path = path;
			workspace = connection.GetWorkspace(path);
			if (workspace != null)
			{
				serverPath = workspace.TryGetServerItemForLocalItem(path);
				txtOwner.Text = workspace.OwnerName;
			}
			else
				txtOwner.Text = Environment.UserDomainName + "\\" + Environment.UserName;
			txtLabelScope.Text = serverPath;
		}


		VirtualViewItem[] VirtualViewItemsLabels = new VirtualViewItem[0];
		VirtualViewItem[] VirtualViewItemsLabelItems = new VirtualViewItem[0];

		private void btnFind_Click(object sender, EventArgs e)
		{

			LoadLabels(string.IsNullOrEmpty(txtOwner.Text) ? null : txtOwner.Text, txtSearchFile.Text,
				string.IsNullOrEmpty(txtLabelName.Text) ? null : txtLabelName.Text,
				string.IsNullOrEmpty(txtLabelScope.Text) ? null : txtLabelScope.Text);
		}

		private void LoadLabels(string owner,string searchFile, string name, string projectPath)
		{
			int v = 0;
			int.TryParse(cmbVersion1.Text, out v);
			VersionSpec versionSpec = VersionSpec.Latest;
			if (v > 0)
				versionSpec = new ChangesetVersionSpec(v);

			VersionControlLabel[] vcls = new VersionControlLabel[0];
			try
			{
				if (!string.IsNullOrEmpty(searchFile))
				{
					string projectName;
					int projectVersion;
					LizardFileAccess.GetNameAndVersionFromPath(projectPath, out projectName, out projectVersion);
					string searchFileName;
					LizardFileAccess.GetNameAndVersionFromPath(searchFile, out searchFileName, out projectVersion);

					vcls = workspace.VersionControlServer.QueryLabels(
						name, projectName, owner, false, searchFileName, versionSpec);
				}
				else
				{
					vcls = workspace.VersionControlServer.QueryLabels(
					 name, projectPath, owner, false);
				}
				VirtualViewItemsLabels = new VirtualViewItem[vcls.Length]; ;
				sortitems[lvwLabels] = VirtualViewItemsLabels;
				lvwLabels.Items.Clear();
				lvwLabels.VirtualListSize = VirtualViewItemsLabels.Length;
				int idx = 0;
				foreach (VersionControlLabel vcl in vcls)
				{
					VirtualViewItemsLabels[idx] = new VirtualViewItem();
					VirtualViewItemsLabels[idx].Items = new string[] { vcl.Name, 
				    vcl.LastModifiedDate.ToShortDateString(), vcl.OwnerName, vcl.Comment
				   , vcl.Scope};
					VirtualViewItemsLabels[idx++].Tag = vcl;
				}
				if (vcls.Length == 0)
					MessageBox.Show("No labels were found for those criteria.",
						"Could Not Find Labels", MessageBoxButtons.OK, MessageBoxIcon.None);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Failed to search for labels due to the following error:\r\n" + ex.Message,
					"Could Not Find Labels", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void cbtTFScopeFinder_Click(object sender, EventArgs e)
		{
			string projectPath = txtSearchFile.Text;
			if (cmbVersion1.SelectedIndex > 1)
			{

			}
				projectPath += ";c" + cmbVersion1.Text;
			TFProjectBrowser tfpb = new TFProjectBrowser(txtSearchFile.Text, ItemType.Any, workspace);
			tfpb.ShowDialog();

			txtSearchFile.Text = tfpb.ProjectPath;
			cmbVersion1.Text = tfpb.ProjectVersion == 0 ? "Latest" : tfpb.ProjectVersion.ToString();
		}

		private void txtScope_TextChanged(object sender, EventArgs e)
		{
			LizardFileAccess.LoadVersions(connection, cmbVersion1, txtSearchFile.Text);
		}

		private void lvwLabels_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (pendingUpdates != null && pendingUpdates.Count > 0)
			{
				DialogResult dr = MessageBox.Show("Do you wish to save the pending label updates before viewing another label?",
					"Save Changes", MessageBoxButtons.YesNo,
					MessageBoxIcon.Question);
				if (dr == DialogResult.Yes)
					UpdateLabel();
			}
			Ltf.MonitorLizard.Helpers.FileIcons fileIcons = new Ltf.MonitorLizard.Helpers.FileIcons(fileImages);
			if (lvwLabels.SelectedIndices.Count == 1)
			{
				btnAdd.Enabled = btnRemove.Enabled = true;
				btnUpdate.Enabled = false;
				pendingUpdates = new Queue<LabelUpdateOperation>();

				VersionControlLabel vcl = (VersionControlLabel)VirtualViewItemsLabels[lvwLabels.SelectedIndices[0]].Tag;

				VersionControlLabel[] vcls = workspace.VersionControlServer.QueryLabels(
					vcl.Name, vcl.Scope, vcl.OwnerName, true);

				vcl = vcls[0];
				currentLabel = vcl;
				lvwItems.Items.Clear();
				lvwItems.SmallImageList = fileImages;
				VirtualViewItemsLabelItems = new VirtualViewItem[vcl.Items.Length];
				sortitems[lvwItems] = VirtualViewItemsLabelItems;
				int idx = 0;

				FileIcons fi = new FileIcons(fileImages);
				lvwItems.SmallImageList = fileImages;
				foreach (Item item in vcl.Items)
				{
					VirtualViewItem vvi = new VirtualViewItem();
					vvi.Items = new string[] { item.ServerItem, item.ChangesetId.ToString() };
					if (item.ItemType == ItemType.Folder)
						vvi.ImageKey = "$folder";
					else
					{
						vvi.ImageKey = fileIcons.LoadIconForFileExtension(System.IO.Path.GetExtension(item.ServerItem));
					}
					VirtualViewItemsLabelItems[idx] = vvi;
					idx++;
					//ListViewItem lvi = new ListViewItem(new string[] { item.ServerItem, item.ChangesetId.ToString() });
					//lvwItems.Items.Add(lvi);
					//if (item.ItemType == ItemType.Folder)
					//  lvi.ImageKey = "$folder";
					//else
					//  lvi.ImageKey = fileIcons.LoadIconForFileExtension(System.IO.Path.GetExtension(item.ServerItem));

				}
				lvwItems.VirtualListSize = vcl.Items.Length;
			}
		}


		Dictionary<ListView, int> sortColumnIndex;
		Dictionary<ListView, bool> sortDesc;
		Dictionary<ListView, VirtualViewItem[]> sortitems;


		void lsvChanges_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			ListView lv = sender as ListView;
			lv.Columns[sortColumnIndex[lv]].ImageKey = null;
			if (sortColumnIndex[lv] == e.Column)
				sortDesc[lv] = !sortDesc[lv];
			else
			{
				sortDesc[lv] = false;
				sortColumnIndex[lv] = e.Column;
			}

			SortListView(lv);
		}

		private void SortListView(ListView lv)
		{
			IComparer<VirtualViewItem> c = new VirtualViewItem.Sorter(sortColumnIndex[lv], sortDesc[lv]);
			List<VirtualViewItem> list = new List<VirtualViewItem>(sortitems[lv]);
			list.Sort(c);
			sortitems[lv] = list.ToArray();

			if (lv == lvwLabels)
				VirtualViewItemsLabels = sortitems[lv];
			else if (lv == lvwItems)
				VirtualViewItemsLabelItems = sortitems[lv];

			lv.Invalidate();
			lv.Refresh();
		}

		private void btnScopePicker_Click(object sender, EventArgs e)
		{
			string projectPath = txtLabelScope.Text;
			TFProjectBrowser tfpb = new TFProjectBrowser(projectPath, ItemType.Any, workspace);
			tfpb.ShowDialog();

			txtLabelScope.Text = tfpb.ProjectPath;
		}

		private void lvwLabels_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
		{
			if (VirtualViewItemsLabels.Length > e.ItemIndex)
			{
				int itemIdx = e.ItemIndex;
				ListViewItem lvi = VirtualViewItemsLabels[itemIdx].ConvertToListViewItem();
				e.Item = lvi;
			}
		}

		private void lvwItems_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
		{
			if (VirtualViewItemsLabelItems.Length > e.ItemIndex)
			{
				int itemIdx = e.ItemIndex;
				ListViewItem lvi = VirtualViewItemsLabelItems[itemIdx].ConvertToListViewItem();
				e.Item = lvi;
			}
		}

		private void btnAdd_Click(object sender, EventArgs e)
		{
			TFProjectBrowser tfpb = new TFProjectBrowser(txtLabelScope.Text, ItemType.Any, workspace, true);
			tfpb.ShowDialog();
			Ltf.MonitorLizard.Helpers.FileIcons fileIcons = new Ltf.MonitorLizard.Helpers.FileIcons(fileImages);
			Dictionary<string, VirtualViewItem> listItems = new Dictionary<string, VirtualViewItem>();
			foreach (VirtualViewItem vvi in VirtualViewItemsLabelItems)
				listItems.Add(vvi.Items[0], vvi);
			foreach (Item i in tfpb.GetSelectedItems())
			{
				if (!listItems.ContainsKey(i.ServerItem))
				{
					LabelUpdateOperation op = new LabelUpdateOperation();
					op.Path = i.ServerItem;
					op.versionSpec = new ChangesetVersionSpec(i.ChangesetId);
					op.Type = LabelUpdateOperationType.Add;
					VirtualViewItem vvi = new VirtualViewItem();
					vvi.Items = new string[] { i.ServerItem, i.ChangesetId.ToString() };
					if (i.ItemType == ItemType.Folder)
						vvi.ImageKey = "$folder";
					else
						vvi.ImageKey = fileIcons.LoadIconForFileExtension(System.IO.Path.GetExtension(i.ServerItem));
					listItems.Add(i.ServerItem, vvi);
					pendingUpdates.Enqueue(op);
					btnUpdate.Enabled = true;
				}
			}
			VirtualViewItemsLabelItems = new VirtualViewItem[listItems.Count];
			listItems.Values.CopyTo(VirtualViewItemsLabelItems, 0);
			lvwItems.VirtualListSize = listItems.Count;
			sortitems[lvwItems] = VirtualViewItemsLabelItems;
			SortListView(lvwItems);
		}

		private void btnRemove_Click(object sender, EventArgs e)
		{
			List<VirtualViewItem> listItems = new List<VirtualViewItem>(VirtualViewItemsLabelItems);
			int offset = 0;
			while (lvwItems.SelectedIndices.Count > 0)
			{
				int idx = lvwItems.SelectedIndices[0];
				lvwItems.SelectedIndices.Remove(idx);
				LabelUpdateOperation op = new LabelUpdateOperation();
				op.Path = VirtualViewItemsLabelItems[idx].Items[0];
				op.versionSpec = new ChangesetVersionSpec(int.Parse(VirtualViewItemsLabelItems[idx].Items[1]));
				op.Type = LabelUpdateOperationType.Remove;
				pendingUpdates.Enqueue(op);
				listItems.RemoveAt(idx - offset++);
				btnUpdate.Enabled = true;
			}
			VirtualViewItemsLabelItems = listItems.ToArray();
			lvwItems.VirtualListSize = listItems.Count;
			sortitems[lvwItems] = VirtualViewItemsLabelItems;
			SortListView(lvwItems);
			lvwItems.RedrawItems(0, listItems.Count - 1, false);
		}

		private void btnUpdate_Click(object sender, EventArgs e)
		{
			UpdateLabel();
		}

		private void UpdateLabel()
		{
			Dictionary<string, LabelUpdateOperation> adds = new Dictionary<string, LabelUpdateOperation>();
			Dictionary<string, LabelUpdateOperation> removes = new Dictionary<string, LabelUpdateOperation>();

			while (pendingUpdates.Count > 0)
			{
				LabelUpdateOperation op = pendingUpdates.Dequeue();
				if (op.Type == LabelUpdateOperationType.Add && !removes.ContainsKey(op.Path))
					adds.Add(op.Path, op);
				if (op.Type == LabelUpdateOperationType.Add && removes.ContainsKey(op.Path))
					removes.Remove(op.Path);

				if (op.Type == LabelUpdateOperationType.Remove && !adds.ContainsKey(op.Path))
					removes.Add(op.Path, op);
				if (op.Type == LabelUpdateOperationType.Remove && adds.ContainsKey(op.Path))
					adds.Remove(op.Path);
			}
			List<LabelItemSpec> liss = new List<LabelItemSpec>();
			foreach (LabelUpdateOperation op in adds.Values)
				liss.Add(new LabelItemSpec(new ItemSpec(op.Path, RecursionType.None), op.versionSpec, false));
			//foreach (LabelUpdateOperation op in removes.Values)
			//  liss.Add(new LabelItemSpec(new ItemSpec(op.Path, RecursionType.None), op.versionSpec, true));
			workspace.VersionControlServer.CreateLabel(currentLabel, liss.ToArray(), LabelChildOption.Merge);

			//			List<ItemSpec> iss = new List<ItemSpec>();
			foreach (LabelUpdateOperation op in removes.Values)
			{
				workspace.VersionControlServer.UnlabelItem(currentLabel.Name, currentLabel.Scope, new ItemSpec[] { new ItemSpec(op.Path, RecursionType.None) }, op.versionSpec);
			}
		}

		private void lvwItems_SelectedIndexChanged(object sender, EventArgs e)
		{

		}

		private void btnNewLabel_Click(object sender, EventArgs e)
		{
			NewLabel nl = new NewLabel(workspace, path);
			nl.ShowDialog();

		}

		private void btnDelete_Click(object sender, EventArgs e)
		{
			if (lvwLabels.SelectedIndices.Count == 0)
				return;

			DialogResult dr = MessageBox.Show("Do you really want to delete all the selection labels? This can not be undone.", "Delete Labels",
				MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
			if (dr == DialogResult.OK)
				DeleteSelectedLabels();
		}

		private void DeleteSelectedLabels()
		{
			foreach (int idx in lvwLabels.SelectedIndices)
			{
				VersionControlLabel vcl = (VersionControlLabel)VirtualViewItemsLabels[lvwLabels.SelectedIndices[idx]].Tag;
				workspace.VersionControlServer.DeleteLabel(vcl.Name, vcl.Scope);

				
			}
			LoadLabels(string.IsNullOrEmpty(txtOwner.Text) ? null : txtOwner.Text, txtSearchFile.Text,
					string.IsNullOrEmpty(txtLabelName.Text) ? null : txtLabelName.Text,
					string.IsNullOrEmpty(txtLabelScope.Text) ? null : txtLabelScope.Text);

		}

		private void btnClose_Click(object sender, EventArgs e)
		{
			Close();
		}

	}

	public enum LabelUpdateOperationType
	{
		Add,
		Remove
	}

	public class LabelUpdateOperation
	{
		public VersionControlLabel Label;
		public LabelUpdateOperationType Type;
		public string Path;
		public VersionSpec versionSpec;
	}

	public class VirtualViewItem
	{
		public string[] Items;
		public string ImageKey;
		public object Tag;
		public bool Checked;

		public int GroupHeaderIdx = 0;
		public int GroupIdx = 0;


		public string Text
		{
			get
			{
				return Items[0];
			}
			set
			{
				if (Items == null)
					Items = new string[] { value };
				else
					Items[0] = value;
			}
		}

		private ListViewGroup group;

		public ListViewGroup Group
		{
			get { return group; }
			set
			{
				group = value;
				GroupIdx = group.ListView.Groups.IndexOf(group);
			}
		}

		private Color foreColor;
		public Color ForeColor
		{
			get { return foreColor; }
			set { foreColor = value; }
		}




		public ListViewItem ConvertToListViewItem()
		{
			ListViewItem lvi = new ListViewItem(Items);
			lvi.Tag = Tag;

			lvi.ImageKey = ImageKey;
			lvi.ForeColor = this.foreColor;
			lvi.Group = this.group;
			lvi.Checked = this.Checked;
			return lvi;
		}

		public class Sorter : IComparer<VirtualViewItem>
		{
			private int sortColumnIndex;
			private int descMultiplier;

			public Sorter(int sortColumnIndex, bool desc)
			{
				this.sortColumnIndex = sortColumnIndex;
				descMultiplier = (desc ? -1 : 1);
			}
			#region IComparer<string[]> Members

			public int Compare(VirtualViewItem x, VirtualViewItem y)
			{
				if (x.Items.Length <= sortColumnIndex)
					return -1;
				if (y.Items.Length <= sortColumnIndex)
					return 1;
				string xText = x.Items[sortColumnIndex];
				string yText = y.Items[sortColumnIndex];

				double xNumber = 0, yNumber = 0;
				DateTime xDate, yDate;
				if (double.TryParse(xText, out xNumber) && double.TryParse(yText, out yNumber))
					return xNumber.CompareTo(yNumber) * descMultiplier;
				else if (DateTime.TryParse(xText, out xDate) && DateTime.TryParse(yText, out yDate))
					return xDate.CompareTo(yDate) * descMultiplier;
				return xText.CompareTo(yText) * descMultiplier;
			}

			#endregion
		}

	}
}